﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace xycn.framework.Common
{
    public static class AssemblyLoader
    {
        public static string errMsg = "";

        /// <summary>
        /// 加载动态库
        /// </summary>
        /// <param name="file">直接加载的库文件（带路径）</param>
        /// <param name="dependency_path">当前环境中已经加载的依赖库</param>
        /// <returns></returns>
        public static Assembly LoadLib(string file, string dependency_path)
        {
            errMsg = "";
            Assembly ret = null;

            //获取运行环境已加载依赖库
            Assembly[] assem_atr = AppDomain.CurrentDomain.GetAssemblies();

            //创建运行环境已加载依赖库字典
            Dictionary<string, Assembly> loaded_dependency =
                new Dictionary<string, Assembly>();
            foreach (Assembly assembly in assem_atr)
            {
                loaded_dependency.TryAdd(assembly.FullName, assembly);
            }

            //加载指定文件
            ret = LoadFile(file, dependency_path, loaded_dependency);

            return ret;
        }

        /// <summary>
        /// 加载指定依赖库文件
        /// </summary>
        /// <param name="file">直接加载的库文件（带路径）</param>
        /// <param name="dependency_path">依赖库所在文件夹</param>
        /// <param name="loaded_dependency">当前已经加载了的依赖库</param>
        /// <returns></returns>
        private static Assembly LoadFile(string file, 
            string dependency_path,
            Dictionary<string, Assembly> loaded_dependency)
        {
            Assembly loading_lib = Assembly.LoadFrom(file);
                //.LoadFile(file);
            //Assembly loading_lib = Assembly.UnsafeLoadFrom(file);

            loaded_dependency.TryAdd(loading_lib.FullName, loading_lib);

            LoadDependency(dependency_path, loading_lib, loaded_dependency);

            return loading_lib;
        }

        /// <summary>
        /// 递归加载依赖库
        /// </summary>
        /// <param name="lib_dir"></param>
        /// <param name="loading_lib"></param>
        /// <param name="loaded_dependency"></param>
        private static void LoadDependency(string lib_dir, Assembly loading_lib, 
            Dictionary<string, Assembly> loaded_dependency)
        {
            //获取依赖
            AssemblyName[] ref_libs =
                loading_lib.GetReferencedAssemblies();

            foreach (AssemblyName ref_lib in ref_libs)
            {
                if (!loaded_dependency.ContainsKey(ref_lib.FullName))
                {
                    string depend_file = ref_lib.CodeBase;
                    if (depend_file == null)
                    {
                        depend_file = lib_dir + Path.DirectorySeparatorChar.ToString() + ref_lib.Name + ".dll";
                    }
                    
                    try
                    {
                        if (File.Exists(depend_file))
                        {
                            LoadFile(depend_file, lib_dir, loaded_dependency);
                        }
                        else
                        {
                            Assembly.Load(ref_lib);
                        }
                    }
                    catch (Exception ex)
                    {
                        errMsg = errMsg + "加载" + ref_lib.Name + "出错：" + ex.Message + "\r\n";
                    }
                }
            }
            return;
        }


    }
}
